﻿/* dk2Repository - Copyright (C) 2011 Daniel Kuczewski http://www.dk2.de/

 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */

using System;
using System.Data;
using System.Reflection;
using dk2Repository.Interfaces;

namespace dk2Repository
{
    internal class Mapping : IMapping
    {
        public Type Type { get; private set; }
        public Columns Columns { get; private set; }
        public References References { get; private set; }
        public EnumPkType PkType { get; private set; }
        public string Table { get; private set; }

        internal Mapping(Type type)
        {
            Type = type;

            Columns = new Columns();
            References = new References();

            var ta = (TableAttribute)Attribute.GetCustomAttribute(type, typeof(TableAttribute));
            if (ta == null)
                Table = type.Name;
            else
                Table = !string.IsNullOrEmpty(ta.Table) ? ta.Table : type.Name;

            foreach (var propertyInfo in type.GetProperties())
            {
                var ca = (ColumnAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ColumnAttribute));
                var ra = (ReferenceAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ReferenceAttribute));

                if (ca == null && ra == null)
                    continue;

                if (ca != null && ra != null)
                    throw new MappingException("Use Reference OR(!) Column");

                if (ca == null) 
                    continue;

                var cm = new Columns.Column(propertyInfo, ca);

                if (Columns.Contains(cm.ColumnName))
                    throw new MappingException("Column " + cm.ColumnName + " already exists");

                Columns.Add(cm);
            }

            foreach (var propertyInfo in type.GetProperties())
            {
                var ra = (ReferenceAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(ReferenceAttribute));

                if (ra == null)
                    continue;

                var prefix = string.IsNullOrEmpty(ra.Prefix) ? propertyInfo.PropertyType.Name + "_" : ra.Prefix;
                var fkcolumn = ra.ForeignKeyColumn;
                var ckcolumn = ra.CandidateKey;

                if (string.IsNullOrEmpty(fkcolumn) || !Columns.Contains(fkcolumn))
                    throw new MappingException("ForeignKeyColumn not found");

                if (string.IsNullOrEmpty(ckcolumn))
                    throw new MappingException("CandidateKeyColumn not found");

                References.Add(new References.Reference(propertyInfo, fkcolumn, ckcolumn, prefix));
            }

            if (Columns.Count == 0)
                throw new MappingException("Missing Property Attributes");

            if (Columns.PrimaryKeys.Length == 0)
                PkType = EnumPkType.None;
            else if (Columns.PrimaryKeys.Length > 1)
                PkType = EnumPkType.Multiple;
            else
            {
                if (Columns.PrimaryKeys[0].IsAutoInc)
                    PkType = EnumPkType.SingleAutoinc;
                else if (Columns.PrimaryKeys[0].IsGuid)
                    PkType = EnumPkType.SingleGuid;
                else
                    PkType = EnumPkType.Single;
            }

        }

        public object CreateInstance()
        {
            return Activator.CreateInstance(Type);
        }



    }

}
